package com.github.qianhe.sdk;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.*;

/**
 * ClassName:QHRequest
 * Function: HTTP请求类，携带证书和不带证书
 * Date:     2019-12-27 下午3:22:33
 *
 * @author Zhang Xingliang
 */
public class QHRequest {

	private QHConfig config;

	public QHRequest(QHConfig config) throws Exception{
		this.config = config;
	}

	public static final int connectTimeoutMs = 8000, readTimeoutMs = 10000;

	public static final String USERAGENT = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36";
	public static final String USERAGENT_FIELD = "User-Agent";
	public static final String CONTENT_TYPE_FIELD = "Content-Type";

	public static final String TEXT_XML = "text/xml";
	public static final String APPLICATION_JSON = "application/json";


	/**
	 * 发送HttpPost请求，参数为map
	 *
	 * @param url 请求地址
	 * @param map 请求参数
	 * @return 返回字符串
	 */
	public static String request(String url, Map<String, String> map) throws Exception {
		return request(url, map, connectTimeoutMs, readTimeoutMs);
	}
	/**
	 * 发送HttpPost请求，参数为map
	 *
	 * @param url 请求地址
	 * @param map 请求参数
	 * @param connectTimeoutMs
	 * @param readTimeoutMs
	 * @return 返回字符串
	 */
	public static String request(String url, Map<String, String> map, int connectTimeoutMs, int readTimeoutMs) throws Exception {
		// 设置参数
		List<NameValuePair> formparams = new ArrayList<NameValuePair>();
		for (String key : map.keySet()) {
			formparams.add(new BasicNameValuePair(key, map.get(key)));
		}
		// 取得HttpPost对象
		HttpPost httpPost = new HttpPost(url);
		//设置超时间
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(readTimeoutMs)
				.setConnectTimeout(connectTimeoutMs).build();
		httpPost.setConfig(requestConfig);
		// 防止被当成攻击添加的
		httpPost.setHeader(USERAGENT_FIELD, USERAGENT);
		// 参数放入Entity
		httpPost.setEntity(new UrlEncodedFormEntity(formparams, Consts.UTF_8));
		// 执行post请求
		BasicHttpClientConnectionManager connManager = setSocketFactory();
		HttpClient httpClient = HttpClientBuilder.create()
				.setConnectionManager(connManager)
				.build();
		HttpResponse httpResponse = httpClient.execute(httpPost);
		HttpEntity httpEntity = httpResponse.getEntity();
		return EntityUtils.toString(httpEntity, Consts.UTF_8);
	}

	/**
	 * 请求，只请求一次，不做重试
	 *
	 * @param url
	 * @param data
	 * @param connectTimeoutMs
	 * @param readTimeoutMs
	 * @param useCert          是否使用证书，针对退款、撤销等操作
	 * @return
	 * @throws Exception
	 */
	private static String requestOnce(final String url, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert
			, InputStream certStream, String password) throws Exception {
		return requestOnce(url,data,null,connectTimeoutMs,readTimeoutMs,useCert,certStream,password);
	}

	/**
	 * 请求，只请求一次，不做重试，自定义请求头
	 *
	 * @param url
	 * @param data json 数据
	 * @param headerMap 请求头信息
	 * @return
	 * @throws Exception
	 */
	public static String requestOnce(final String url, String data, Map<String, String> headerMap) throws Exception {
		return requestOnce(url,data,headerMap,connectTimeoutMs,readTimeoutMs,false,null,null);
	}

	/**
	 * 请求，只请求一次，不做重试
	 *
	 * @param url
	 * @param data
	 * @param headerMap 请求头
	 * @param connectTimeoutMs
	 * @param readTimeoutMs
	 * @param useCert          是否使用证书，针对退款、撤销等操作
	 * @return
	 * @throws Exception
	 */
	private static String requestOnce(final String url, String data, Map<String, String> headerMap, int connectTimeoutMs, int readTimeoutMs, boolean useCert
			, InputStream certStream, String password) throws Exception {

		BasicHttpClientConnectionManager connManager = useCert ? setSSLSocketFactory(certStream, password) : setSocketFactory();

		HttpClient httpClient = HttpClientBuilder.create()
				.setConnectionManager(connManager)
				.build();

		HttpPost httpPost = new HttpPost(url);

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
		httpPost.setConfig(requestConfig);
		StringEntity postEntity;

		// 防止被当成攻击添加的
		//httpPost.setHeader("User-Agent", USERAGENT);

		if(null != headerMap){
			postEntity = new StringEntity(data, ContentType.APPLICATION_JSON);
			for (String key : headerMap.keySet()) {
				httpPost.addHeader(key, headerMap.get(key));
			}
		}else{
			postEntity = new StringEntity(data, Consts.UTF_8);
			httpPost.addHeader(CONTENT_TYPE_FIELD, TEXT_XML);
		}

		httpPost.setEntity(postEntity);

		HttpResponse httpResponse = httpClient.execute(httpPost);
		HttpEntity httpEntity = httpResponse.getEntity();
		return EntityUtils.toString(httpEntity, Consts.UTF_8);
	}

	private static BasicHttpClientConnectionManager setSocketFactory() {
		return new BasicHttpClientConnectionManager(
				RegistryBuilder.<ConnectionSocketFactory>create()
						.register("http", PlainConnectionSocketFactory.getSocketFactory())
						.register("https", SSLConnectionSocketFactory.getSocketFactory())
						.build(),
				null,
				null,
				null
		);
	}

	private static BasicHttpClientConnectionManager setSSLSocketFactory(InputStream certStream, String password) throws Exception {
		// 证书
		char[] pwd = password.toCharArray();
		KeyStore ks = KeyStore.getInstance("PKCS12");
		ks.load(certStream, pwd);
		// 实例化密钥库 & 初始化密钥工厂
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
		kmf.init(ks, pwd);

		// 创建 SSLContext
		SSLContext sslContext = SSLContext.getInstance("TLS");
		sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());

		SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
				sslContext,
				new String[]{"TLSv1"},
				null,
				new DefaultHostnameVerifier());

		return new BasicHttpClientConnectionManager(
				RegistryBuilder.<ConnectionSocketFactory>create()
						.register("http", PlainConnectionSocketFactory.getSocketFactory())
						.register("https", sslConnectionSocketFactory)
						.build(),
				null,
				null,
				null
		);
	}

	/**
	 * @param request
	 * @return java.lang.String
	 * @author Zhang Xingliang
	 * @description 获取请求HttpServletRequest 中参数 转String
	 * @date 18:51 2020/2/17
	 **/
	public static String getRequestString(HttpServletRequest request) {
		StringBuilder sb = new StringBuilder();
		try (BufferedReader reader = request.getReader();) {
			char[] buff = new char[1024];
			int len;
			while ((len = reader.read(buff)) != -1) {
				sb.append(buff, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}

	/**
	 * @param request
	 * @return Map<String, String>
	 * @author Zhang Xingliang
	 * @description 获取请求HttpServletRequest 中参数 转Map<String, String>
	 * @date 13:11 2020/7/15
	 **/
	public static Map<String, String> getRequestMap(HttpServletRequest request) {
		Map<String, String> requestMap = new HashMap<String, String>();
		Map<String, String[]> requestParams = request.getParameterMap();
		Iterator iterator = requestParams.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<String, String[]> entry = (Map.Entry) iterator.next();
			String field = (String) entry.getKey();
			String[] values = (String[]) entry.getValue();
			StringBuilder sb = new StringBuilder();
			for (String value : values) {
				sb.append(value).append(",");
			}
			sb.setLength(sb.length() - 1);
			requestMap.put(field, sb.toString());
		}
		return requestMap;
	}


	/**
	 * 处理 HTTPS API返回数据，转换成Map对象
	 *
	 * @param respJsonData API返回的JSON格式数据
	 * @return Map类型数据
	 * @throws Exception
	 */
	public Map<String, String> responseSignJson(String respJsonData) throws Exception {
		// 1.Feature.OrderedField 按字符串原有顺序排序
//		JSONObject respJsonData = (JSONObject) JSONObject.parse(jsonStr, Feature.OrderedField);

		// 2.初始化json对象为有序对象
		//JSONObject respJsonData = new JSONObject(true);

		// 3.使用Gson解析 解析时参数不调整顺序
		//JsonObject respJsonData = new JsonParser().parse(jsonStr).getAsJsonObject();
		return QHUtil.Json.parse(respJsonData, Map.class);
	}
}
